package com.bigpay.app.polling.core;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.bigpay.account.enums.SettRecordStatusEnum;
import com.bigpay.account.service.RpSettHandleService;
import com.bigpay.app.polling.entity.PollingParam;
import com.bigpay.banklink.vo.DeductPayQueryParam;
import com.bigpay.banklink.vo.DeductPayQueryResult;
import com.bigpay.banklink.vo.ProxyPayParam;
import com.bigpay.banklink.vo.ProxyPayQueryParam;
import com.bigpay.banklink.vo.ProxyPayQueryResult;
import com.bigpay.banklink.vo.QuickPayQueryParam;
import com.bigpay.banklink.vo.QuickPayQueryResult;
import com.bigpay.banklink.weixin.BankCnpPayService;
import com.bigpay.common.core.config.MqConfig;
import com.bigpay.common.core.id.IdGenerator;
import com.bigpay.common.core.page.PageBean;
import com.bigpay.common.core.page.PageParam;
import com.bigpay.notify.entity.RpNotifyRecord;
import com.bigpay.notify.entity.RpNotifyRecordLog;
import com.bigpay.notify.enums.NotifyStatusEnum;
import com.bigpay.notify.enums.NotifyTypeEnum;
import com.bigpay.notify.service.RpNotifyService;
import com.bigpay.trade.enums.TradeStatusEnum;
import com.bigpay.trade.service.RpTradePaymentManagerService;

/**
 * <b>功能说明:
 * TODO... 无注释
 */
@Service("pollingPersist")
public class PollingPersist {

    private static final Logger LOG = LoggerFactory.getLogger(PollingPersist.class);

    @Autowired
    private RpNotifyService rpNotifyService;

    @Autowired
    private PollingParam pollingParam;

    @Autowired
    private PollingQueue pollingQueue;

    @Autowired
    private BankCnpPayService bankCnpPayService;

    @Autowired
    private RpSettHandleService rpSettHandleService;

    @Autowired
    private RpTradePaymentManagerService rpTradePaymentManagerService;
    
    @Autowired
    private JmsTemplate jmsTemplate;
    
    @Autowired
    private IdGenerator idGenerator;
    
    /**
     * 创建代付结果查询记录.<br/>
     *
     * @param notifyRecord
     * @return
     */
    public long saveNotifyRecord(RpNotifyRecord notifyRecord) {
        return rpNotifyService.createNotifyRecord(notifyRecord);
    }

    /**
     * 更新代付结果查询记录.<br/>
     *
     * @param id
     * @param notifyTimes
     *            通知次数.<br/>
     * @param status
     *            通知状态.<br/>
     * @return 更新结果
     */
    public  void updateNotifyRord(Long id, int notifyTimes, String status, Date editTime) {
        RpNotifyRecord notifyRecord = rpNotifyService.getNotifyRecordById(id);
        notifyRecord.setNotifyTimes(notifyTimes);
        notifyRecord.setStatus(status);
        notifyRecord.setEditTime(editTime);
        notifyRecord.setLastNotifyTime(editTime);
        rpNotifyService.updateNotifyRecord(notifyRecord);
    }

    /**
     * 创建代付结果查询记录.<br/>
     *
     * @param notifyId
     *            查询记录ID.<br/>
     * @param merchantNo
     *            商户编号.<br/>
     * @param merchantOrderNo
     *            商户订单号.<br/>
     * @param request
     *            请求信息.<br/>
     * @param response
     *            返回信息.<br/>
     * @param httpStatus
     *            通知状态(HTTP状态).<br/>
     * @return 创建结果
     */
    public long saveNotifyRecordLogs(Long notifyId, String merchantNo, String merchantOrderNo, String request, String response, int httpStatus) {

        RpNotifyRecordLog notifyRecordLog = new RpNotifyRecordLog();
        notifyRecordLog.setId(idGenerator.getNotifyRecordLogId());
        notifyRecordLog.setNotifyId(notifyId);
        notifyRecordLog.setMerchantNo(merchantNo);
        notifyRecordLog.setMerchantOrderNo(merchantOrderNo);
        notifyRecordLog.setRequest(request);
        notifyRecordLog.setResponse(response);
        notifyRecordLog.setHttpStatus(httpStatus);
        notifyRecordLog.setCreateTime(new Date());
        notifyRecordLog.setEditTime(new Date());
        return rpNotifyService.createNotifyRecordLog(notifyRecordLog);

    }

    /**
     * 获取代付结果
     * @param proxyPayQueryParam
     */
    @Transactional(rollbackFor = Exception.class)
    public void getProxyPayQueryResult(ProxyPayQueryParam proxyPayQueryParam ,RpNotifyRecord notifyRecord){

        ProxyPayQueryResult proxyPayQueryResult = bankCnpPayService.proxyPayQuery(proxyPayQueryParam);

        Integer notifyTimes = notifyRecord.getNotifyTimes(); // 得到当前通知对象的通知次数
        Integer maxNotifyTimes = notifyRecord.getLimitNotifyTimes(); // 最大通知次数
        Date notifyTime = new Date(); // 本次通知的时间

        LOG.info("proxyPayQueryResult:{}" ,proxyPayQueryResult);
        notifyRecord.setEditTime(notifyTime); // 取本次通知时间作为最后修改时间
        notifyRecord.setNotifyTimes(notifyTimes + 1); // 通知次数+1
        if (proxyPayQueryResult != null){//获取到结算信息
            saveNotifyRecordLogs(notifyRecord.getId(), notifyRecord.getMerchantNo(), notifyRecord.getMerchantOrderNo(), notifyRecord.getUrl(), "", proxyPayQueryResult.getHttpRequestStatus());

            if (SettRecordStatusEnum.REMIT_SUCCESS.equals(proxyPayQueryResult.getSettRecordStatus())){//结算成功
                rpTradePaymentManagerService.setProxyPayResult(proxyPayQueryParam.getRemitRequestNo(), proxyPayQueryParam.getBankChannelCode(), SettRecordStatusEnum.REMIT_SUCCESS , "打款成功");
                updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.SUCCESS.name(), notifyTime);
                return;
            }

            if (SettRecordStatusEnum.REMIT_FAIL.equals(proxyPayQueryResult.getSettRecordStatus())){//结算失败
                rpTradePaymentManagerService.setProxyPayResult(proxyPayQueryParam.getRemitRequestNo(), proxyPayQueryParam.getBankChannelCode(), SettRecordStatusEnum.REMIT_FAIL , proxyPayQueryResult.getRemitDesc());
                updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.SUCCESS.name(), notifyTime);
                return;
            }

            if (SettRecordStatusEnum.REMITTING.equals(proxyPayQueryResult.getSettRecordStatus())){//结算失败
                // 通知不成功（返回的结果不是success）
                if (notifyRecord.getNotifyTimes() < maxNotifyTimes) {
                    // 判断是否超过重发次数，未超重发次数的，再次进入延迟发送队列
                    pollingQueue.addToNotifyTaskDelayQueue(notifyRecord);
                    updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.HTTP_REQUEST_SUCCESS.name(), notifyTime);
                    LOG.info("===>update NotifyRecord status to HTTP_REQUEST_SUCCESS, notifyId: {}", notifyRecord.getId());
                } else {
                    // 到达最大通知次数限制，标记为通知失败
                    updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.FAILED.name(), notifyTime);
                    LOG.info("===>update NotifyRecord status to failed, notifyId:{}", notifyRecord.getId());
                }
            }
        }else{
            saveNotifyRecordLogs(notifyRecord.getId(), notifyRecord.getMerchantNo(), notifyRecord.getMerchantOrderNo(), notifyRecord.getUrl(), "", 0);

            // 通知不成功（返回的结果不是success）
            if (notifyRecord.getNotifyTimes() < maxNotifyTimes) {
                // 判断是否超过重发次数，未超重发次数的，再次进入延迟发送队列
                pollingQueue.addToNotifyTaskDelayQueue(notifyRecord);
                updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.HTTP_REQUEST_SUCCESS.name(), notifyTime);
                LOG.info("===>update NotifyRecord status to HTTP_REQUEST_SUCCESS, notifyId:{}", notifyRecord.getId());
            } else {
                // 到达最大通知次数限制，标记为通知失败
                updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.FAILED.name(), notifyTime);
                LOG.info("===>update NotifyRecord status to failed, notifyId:{}", notifyRecord.getId());
            }
        }
    }


    @Transactional(rollbackFor = Exception.class)
    public void getQuickPayQueryResult(QuickPayQueryParam quickPayQueryParam ,RpNotifyRecord notifyRecord){
        QuickPayQueryResult quickPayQueryResult = rpTradePaymentManagerService.quickPayResultQuery(quickPayQueryParam);

        Integer notifyTimes = notifyRecord.getNotifyTimes(); // 得到当前通知对象的通知次数
        Integer maxNotifyTimes = notifyRecord.getLimitNotifyTimes(); // 最大通知次数
        Date notifyTime = new Date(); // 本次通知的时间

        LOG.info("quickPayQueryResult:{}" ,quickPayQueryResult);
        notifyRecord.setEditTime(notifyTime); // 取本次通知时间作为最后修改时间
        notifyRecord.setNotifyTimes(notifyTimes + 1); // 通知次数+1
        if (quickPayQueryResult != null){//获取到结算信息
            saveNotifyRecordLogs(notifyRecord.getId(), notifyRecord.getMerchantNo(), notifyRecord.getMerchantOrderNo(), notifyRecord.getUrl(), "", 200);

            if (TradeStatusEnum.SUCCESS.equals(quickPayQueryResult.getTradeStatusEnum()) || TradeStatusEnum.FAILED.equals(quickPayQueryResult.getTradeStatusEnum())) {
                LOG.info("快捷支付订单:{}的状态为:{},进行结果处理" , quickPayQueryResult.getBankOrderNo() , quickPayQueryResult.getTradeStatusEnum().name());
                updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.SUCCESS.name(), notifyTime);
                return;
            }  else {
                LOG.info("快捷支付订单:{}的状态为:{},不做结果处理" , quickPayQueryResult.getBankOrderNo() , quickPayQueryResult.getTradeStatusEnum().name());
                // 通知不成功（返回的结果不是success）
                if (notifyRecord.getNotifyTimes() < maxNotifyTimes) {
                    // 判断是否超过重发次数，未超重发次数的，再次进入延迟发送队列
                    pollingQueue.addToNotifyTaskDelayQueue(notifyRecord);
                    updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.HTTP_REQUEST_SUCCESS.name(), notifyTime);
                    LOG.info("===>update NotifyRecord status to HTTP_REQUEST_SUCCESS, notifyId: {}", notifyRecord.getId());
                } else {
                    // 到达最大通知次数限制，标记为通知失败
                    updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.FAILED.name(), notifyTime);
                    LOG.info("===>update NotifyRecord status to failed, notifyId:{}", notifyRecord.getId());
                }
            }
        }else{
            saveNotifyRecordLogs(notifyRecord.getId(), notifyRecord.getMerchantNo(), notifyRecord.getMerchantOrderNo(), notifyRecord.getUrl(), "", 0);

            // 通知不成功（返回的结果不是success）
            if (notifyRecord.getNotifyTimes() < maxNotifyTimes) {
                // 判断是否超过重发次数，未超重发次数的，再次进入延迟发送队列
                pollingQueue.addToNotifyTaskDelayQueue(notifyRecord);
                updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.HTTP_REQUEST_SUCCESS.name(), notifyTime);
                LOG.info("===>update NotifyRecord status to HTTP_REQUEST_SUCCESS, notifyId:{}", notifyRecord.getId());
            } else {
                // 到达最大通知次数限制，标记为通知失败
                updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.FAILED.name(), notifyTime);
                LOG.info("===>update NotifyRecord status to failed, notifyId:{}", notifyRecord.getId());
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void getDeductPayQueryResult(DeductPayQueryParam deductPayQueryParam ,RpNotifyRecord notifyRecord){

        DeductPayQueryResult deductPayQueryResult = rpTradePaymentManagerService.deductPayResultQuery(deductPayQueryParam);

        Integer notifyTimes = notifyRecord.getNotifyTimes(); // 得到当前通知对象的通知次数
        Integer maxNotifyTimes = notifyRecord.getLimitNotifyTimes(); // 最大通知次数
        Date notifyTime = new Date(); // 本次通知的时间

        LOG.info("quickPayQueryResult:{}" ,deductPayQueryResult);
        notifyRecord.setEditTime(notifyTime); // 取本次通知时间作为最后修改时间
        notifyRecord.setNotifyTimes(notifyTimes + 1); // 通知次数+1
        if (deductPayQueryResult != null){//获取到结算信息
            saveNotifyRecordLogs(notifyRecord.getId(), notifyRecord.getMerchantNo(), notifyRecord.getMerchantOrderNo(), notifyRecord.getUrl(), "", 200);


            if (TradeStatusEnum.SUCCESS.equals(deductPayQueryResult.getTradeStatusEnum()) || TradeStatusEnum.FAILED.equals(deductPayQueryResult.getTradeStatusEnum())) {
                LOG.info("代扣支付订单:{}的状态为:{},进行结果处理" , deductPayQueryResult.getBankOrderNo() , deductPayQueryResult.getTradeStatusEnum().name());
                updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.SUCCESS.name(), notifyTime);
                return;
            }  else {
                LOG.info("快捷支付订单:{}的状态为:{},不做结果处理" , deductPayQueryResult.getBankOrderNo() , deductPayQueryResult.getTradeStatusEnum().name());
                // 通知不成功（返回的结果不是success）
                if (notifyRecord.getNotifyTimes() < maxNotifyTimes) {
                    // 判断是否超过重发次数，未超重发次数的，再次进入延迟发送队列
                    pollingQueue.addToNotifyTaskDelayQueue(notifyRecord);
                    updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.HTTP_REQUEST_SUCCESS.name(), notifyTime);
                    LOG.info("===>update NotifyRecord status to HTTP_REQUEST_SUCCESS, notifyId: {}", notifyRecord.getId());
                } else {
                    // 到达最大通知次数限制，标记为通知失败
                    updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.FAILED.name(), notifyTime);
                    LOG.info("===>update NotifyRecord status to failed, notifyId:{}", notifyRecord.getId());
                }
            }
        }else{
            saveNotifyRecordLogs(notifyRecord.getId(), notifyRecord.getMerchantNo(), notifyRecord.getMerchantOrderNo(), notifyRecord.getUrl(), "", 0);

            // 通知不成功（返回的结果不是success）
            if (notifyRecord.getNotifyTimes() < maxNotifyTimes) {
                // 判断是否超过重发次数，未超重发次数的，再次进入延迟发送队列
                pollingQueue.addToNotifyTaskDelayQueue(notifyRecord);
                updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.HTTP_REQUEST_SUCCESS.name(), notifyTime);
                LOG.info("===>update NotifyRecord status to HTTP_REQUEST_SUCCESS, notifyId:{}", notifyRecord.getId());
            } else {
                // 到达最大通知次数限制，标记为通知失败
                updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.FAILED.name(), notifyTime);
                LOG.info("===>update NotifyRecord status to failed, notifyId:{}", notifyRecord.getId());
            }
        }
    }

    /**
     * 发起代付
     * @param proxyPayParam
     * @param notifyRecord
     */
    @Transactional(rollbackFor = Exception.class)
    public void sendProxyPay(ProxyPayParam proxyPayParam ,RpNotifyRecord notifyRecord){
    	
        Date notifyTime = new Date(); // 本次通知的时间
        Integer notifyTimes = notifyRecord.getNotifyTimes(); // 得到当前通知对象的通知次数
        notifyRecord.setEditTime(notifyTime); // 取本次通知时间作为最后修改时间
        notifyRecord.setNotifyTimes(notifyTimes + 1); // 通知次数+1
        updateNotifyRord(notifyRecord.getId(), notifyRecord.getNotifyTimes(), NotifyStatusEnum.SUCCESS.name(), notifyTime);
    	saveNotifyRecordLogs(notifyRecord.getId(), notifyRecord.getMerchantNo(), notifyRecord.getMerchantOrderNo(), notifyRecord.getUrl(), "", 0);
        //发起代付
        LOG.info("begin proxyPay,id:"+notifyRecord.getId());
        ProxyPayQueryParam proxyPayQueryParam = rpTradePaymentManagerService.proxyPay(proxyPayParam);
        LOG.info("end proxyPay");
        String queue = MqConfig.PROXY_PAY_QUERY_QUEUE;
        LOG.info("发起MQ代付查询开始 queue："+ queue);
         
        Object toJSON = JSONObject.toJSON(proxyPayQueryParam);
        String proxyMsg = toJSON.toString();
        RpNotifyRecord record = new RpNotifyRecord();
        record.setId(idGenerator.getNotifyRecordId());
        record.setNotifyTimes(0);
        record.setLimitNotifyTimes(5);
        record.setStatus(NotifyStatusEnum.CREATED.name());
        record.setUrl(proxyMsg);
        record.setMerchantOrderNo(proxyPayParam.getBankOrderNo());
        record.setMerchantNo(proxyPayParam.getMerchantNo());
        record.setNotifyType(NotifyTypeEnum.PROXY_PAY_RESULT_SEARCH.name());

        LOG.info("转换数据开始");
        Object toJSON2 = JSONObject.toJSON(record);
        final String str = toJSON2.toString();
        LOG.info("转换数据结束");
        jmsTemplate.setDefaultDestinationName(queue);
        try {
        	jmsTemplate.send(new MessageCreator() {
                public Message createMessage(Session session) throws JMSException {
                    return session.createTextMessage(str);
                }
            });
        }catch (Exception e){
            LOG.error("代付查询发起异常:" , e);
        }

        LOG.info("发起MQ代付查询结束");
    }

    /**
     * 从数据库中取一次数据用来当系统启动时初始化
     */
    public void initNotifyDataFromDB() {
        LOG.info("===>init get notify data from database");

        int pageNum = 1; // 当前页
        int numPerPage = 10; // 每页记录数
        PageParam pageParam = new PageParam(pageNum, numPerPage);

        List<RpNotifyRecord> recordList = new ArrayList<RpNotifyRecord>(); // 每次拿到的结果集

        // 组装查询条件，通知状态不成功，并且还没有超过最大通知次数的
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("statusNotSuccess", "statusNotSuccess"); // 不是成功状态
        paramMap.put("statusNotFailed", "statusNotFailed"); // 不是失败状态
        paramMap.put("maxNotifyTimes", pollingParam.getMaxNotifyTimes());

        List<String> notifyTypeList = new ArrayList<String>();
        notifyTypeList.add(NotifyTypeEnum.PROXY_PAY_RESULT_SEARCH.name());//代付结果查询
        notifyTypeList.add(NotifyTypeEnum.QUICK_PAY_RESULT_SEARCH.name());//快捷支付查询
        notifyTypeList.add(NotifyTypeEnum.DEDUCT_PAY_RESULT_SEARCH.name());//代扣支付查询
        paramMap.put("notifyTypeList", notifyTypeList);//通知类型为代付结果查询
//        paramMap.put("notifyType", NotifyTypeEnum.PROXY_PAY_RESULT_SEARCH.name());//通知类型为代付结果查询

        // >>>>>>>>>> 查第一页开始 >>>>>>>>>>
        LOG.info("==>pageNum:" + pageNum + ", numPerPage:" + numPerPage);
        PageBean<RpNotifyRecord> pageBean = rpNotifyService.queryNotifyRecordListPage(pageParam, paramMap);
        recordList = pageBean.getRecordList();
        if (recordList == null || recordList.isEmpty()) {
            LOG.info("==>recordList is empty");
            return;
        }
        LOG.info("==>now page size:" + recordList.size());

        int totalPage = pageBean.getTotalPage(); //总页数
        int totalCount = pageBean.getTotalCount(); // 总记录数
        LOG.info("===>totalPage:" + totalPage);
        LOG.info("===>totalCount:" + totalCount);

        for (RpNotifyRecord notifyRecord : recordList) {
            pollingQueue.addToNotifyTaskDelayQueue(notifyRecord);
        }

        // 如果有第2页或以上页
        for (pageNum = 2; pageNum <= totalPage; pageNum++) {
            LOG.info("==>pageNum:" + pageNum + ", numPerPage:" + numPerPage);
            pageBean = rpNotifyService.queryNotifyRecordListPage(new PageParam(pageNum, numPerPage), paramMap);
            recordList = pageBean.getRecordList();
            if (recordList == null || recordList.isEmpty()) {
                LOG.info("==>recordList is empty");
                return;
            }
            LOG.info("==>now page size:" + recordList.size());

            for (RpNotifyRecord notifyRecord : recordList) {
                pollingQueue.addToNotifyTaskDelayQueue(notifyRecord);
            }
        }
    }

}
